2026-09-20 · linux, class-notes
A graphical file manager is fine for moving one file. But consider this task: copy every HTML file from one directory to another, but only files that don't exist in the destination or are newer than the copies there.…
Class notes · William Shotts, The Linux Command Line · Chapter 4
Quick reference: the short version of this chapter is the Chapter 4 cheat sheet.
By the end of these notes you should be able to:
A graphical file manager is fine for moving one file. But consider this task: copy every HTML file from one directory to another, but only files that don't exist in the destination or are newer than the copies there. In a file manager that's tedious and error-prone. On the command line it's one line:
cp -u *.html destinationThe power comes from combining small commands with wildcards, and it scales to thousands of files as easily as to two.
Wildcards (also called globbing) let you name groups of files by pattern. The shell expands the pattern into a list of matching names before the command even runs.
Wildcard
Matches
*
Any characters — including none
?
Exactly one character
[characters]
Any one character from the set
[!characters]
Any one character not in the set
[[:class:]]
Any one character in the named class
Class
Matches
[:alnum:]
Letters and digits
[:alpha:]
Letters
[:digit:]
Digits 0–9
[:lower:]
Lower-case letters
[:upper:]
Upper-case letters
Note the double brackets when used as a wildcard: the outer [ ] is the set, and [:upper:] is the class inside it — [[:upper:]].
A directory contains:
a.txt b.txt c.log BACKUP.1 data1.csv data2.csv data10.csv notes.TXT .hidden
Pattern
Matches
Why
*
Everything except .hidden
* doesn't match a leading dot
*.txt
a.txt b.txt
Case-sensitive: notes.TXT doesn't match
data?.csv
data1.csv data2.csv
? is exactly one character, so data10.csv doesn't match
data*.csv
All three data files
* allows any number of characters
[abc]*
a.txt b.txt c.log
Starts with a, b or c
[[:upper:]]*
BACKUP.1
Starts with a capital letter
*[[:digit:]]*
BACKUP.1 and the three data files
Contains a digit anywhere
Because the shell does the expansion, you can preview any pattern safely with echo or ls before using it with a destructive command:
echo *.log \
ls -d data* \
If nothing matches, Bash passes the pattern through unchanged: echo nomatch*.zip prints nomatch*.zip.
Caution: ranges like [a-z] can behave unexpectedly, because in some language settings the range includes upper-case letters too. Character classes such as [[:lower:]] are predictable, so prefer them.
mkdir dir1 \
mkdir dir1 dir2 dir3 \
mkdir -p projects/2026/notes \
cp has two forms:
cp item1 item2 \
cp item... directory \
Option
Long form
Does
-a
--archive
Copy everything, preserving owner, permissions, timestamps and links — a faithful copy
-i
--interactive
Ask before overwriting an existing file
-r
--recursive
Copy directories and their contents (required for directories)
-u
--update
Only copy files that are missing or newer than the destination
-v
--verbose
Show each file as it's copied
Command
Result
cp file1 file2
Copies file1 to file2. If file2 exists, it's silently overwritten
cp -i file1 file2
Same, but asks first if file2 exists
cp file1 file2 dir1
Copies both files into dir1, which must already exist
cp dir1/* dir2
Copies every (non-hidden) file in dir1 into dir2
cp -r dir1 dir2
If dir2 doesn't exist, creates it as a copy of dir1. If it does, creates dir2/dir1
cp -a /etc/ssh ~/ssh-backup
A faithful copy of a config directory before editing it
The cp -r dir1 dir2 behaviour catches everyone out once. Whether the destination already exists changes the result.
mv both moves and renames; they're the same operation (changing a file's path). The original disappears.
mv item1 item2 \
mv item... directory \
Option
Does
-i
Ask before overwriting
-u
Only move if the source is newer or the destination is missing
-v
Show what's happening
Command
Result
mv file1 file2
Renames file1 to file2 — overwriting file2 if it exists
mv file1 file2 dir1
Moves both files into dir1
mv dir1 dir2
Renames dir1 to dir2 — or, if dir2 exists, moves dir1 inside it
Note: mv needs no -r. Moving a directory moves everything inside it.
rm item...
Option
Does
-i
Ask before each deletion
-r
Delete directories and everything in them, recursively
-f
Force: never ask, ignore missing files (overrides -i)
-v
Show what's deleted
rmdir removes empty directories only, which makes it a safe choice when that's all you intend.
Linux has no recycle bin on the command line. Once rm deletes something, it's gone (recovery tools may sometimes help, but don't count on it). And Linux assumes you know what you're doing — it won't ask "are you sure?" unless you use -i.
You want to delete the HTML files in the current directory:
rm *.html \
rm * .html \
That "ls first, then swap in rm" habit is worth building from day one.
ln file link \
ln -s item link \
A file's data sits on disk; a directory entry is just a name pointing to it. A hard link adds another name for the same data.
A symbolic link is a small special file containing the path to its target.
$ echo "v1" > fun $ ln fun fun-hard $ ln -s fun fun-sym $ ls -li fun* 2801712 -rw-r--r-- 2 andrew andrew 3 Sep 19 14:42 fun 2801712 -rw-r--r-- 2 andrew andrew 3 Sep 19 14:42 fun-hard 2801713 lrwxrwxrwx 1 andrew andrew 3 Sep 19 14:42 fun-sym -> fun1. -i shows the inode number in the first column — the ID of the data on disk. fun and fun-hard share 2801712: two names, one file. 2. Their link count is 2. 3. fun-sym has its own inode and just contains the path fun.
Now delete the original:
$ rm fun $ cat fun-hard v1 $ cat fun-sym cat: fun-sym: No such file or directoryThe hard link still reaches the data; the symbolic link points at a name that no longer exists.
A symlink's target is stored exactly as you type it:
Practise somewhere nothing matters. This sequence exercises everything in the chapter:
cd ~ mkdir playground && cd playground mkdir dir1 dir2 cp /etc/passwd . \
ls -l cp -v passwd dir1 \
mv passwd fun \
mv fun dir1 && mv dir1/fun dir2 \
mv dir2/fun . \
ln fun fun-hard \
ln -s fun fun-sym \
ls -li cd ~ && rm -r playground \
Term
Definition
Wildcard / globbing
Patterns the shell expands into matching filenames
*
Matches any characters, including none
?
Matches exactly one character
Character class
A named set such as [:digit:], used as [[:digit:]]
mkdir -p
Create a directory and any missing parents
cp -a
Archive copy, preserving attributes
cp -r
Recursive copy (needed for directories)
cp -u
Copy only missing or newer files
mv
Move or rename
rm -r
Delete a directory and its contents
rm -f
Force deletion without prompting
rmdir
Remove an empty directory
Directory entry
A name that points to a file's data
Inode
The on-disk record identifying a file's data and attributes
Hard link
An additional name for the same inode
Symbolic link
A special file containing a path to its target
Dangling link
A symlink whose target no longer exists
Playground
A throwaway directory for safe practice